﻿using Red.Controls.ViewModels;
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Red.Controls.Converters;

namespace Red.Controls.DataDriven
{
    [InteropControl( "String:Restricted", "StringAnsi:Restricted", "CName:Restricted" )]
    public class RestrictedDataBox : ComboBox
    {
        #region Data

        private DataItem _optionsItem;

        #endregion Data

        #region Properties

        // Property used for selected value validation - if the combobox clears selection when itemsSource changes, it prevents from sending null value to the engine
        // (as this can result in errors, i.e. when parsing value)
        public static readonly DependencyProperty FallbackValueProperty =
            DependencyProperty.Register( "FallbackValue", typeof( string ), typeof( RestrictedDataBox ), new PropertyMetadata( "Choose value" ), ValidateValue );

        public string FallbackValue
        {
            get { return (string)GetValue( FallbackValueProperty ); }
            set { SetValue( FallbackValueProperty, value ); }
        }

        #endregion Properties

        #region C-tor

        public RestrictedDataBox()
        {
            DisplayMemberPath = "Value";    // we're gonna bind a collection of DataItems to comboBox source, so let's indicate to display their Value in the selection list
            SelectedValuePath = "Value";    // we're gonna bind DataItem's Value to the selectedValue property, so this indicates that DataItem's Value will change when changing selection
            
            Initialized += RestrictedDataBox_Initialized;
            DropDownOpened += RestrictedDataBox_DropDownOpened;
            DropDownClosed += RestrictedDataBox_DropDownClosed;

            SetBinding( SelectedValueProperty, new Binding( "FallbackValue" )
            {
                Source = this,
                Mode = BindingMode.TwoWay,
                UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
            } );

            SetBinding( FallbackValueProperty, new Binding( "Value" )
            {
                Mode = BindingMode.TwoWay,
                UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
            } );

            SetBinding( IsEnabledProperty, new Binding( "IsReadOnly" )
            {
                UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                Converter = new BoolInverter()
            } );
        }

        #endregion C-tor

        #region Event handlers

        private void RestrictedDataBox_DropDownClosed( object sender, EventArgs e )
        {
            // selected item gets cleared every time ItemsSource changes - update the binding to make sure actual property value is displayed
            GetBindingExpression( SelectedValueProperty ).UpdateTarget();
        }

        private async void RestrictedDataBox_DropDownOpened( object sender, EventArgs e )
        {
            // rebuild drop down items in case the possible options list changes over time
            await _optionsItem.RebuildAsync();
        }

        private async void RestrictedDataBox_Initialized( object sender, EventArgs e )
        {
            await BindOptions();
            DataContextChanged += async ( s, arg ) => await BindOptions();
        }

        #endregion Event handlers

        #region Private methods

        private async Task BindOptions()
        {
            if ( DataContext != null )
            {
                var parentItem = (DataItem)DataContext;
                _optionsItem = await parentItem.DigUpSubItemAsync( "_options" );
                await _optionsItem.RebuildAsync();

                SetBinding( ItemsSourceProperty, new Binding() { Source = _optionsItem.Children } );
            }
        }

        private static bool ValidateValue( object value )
        {
            return !string.IsNullOrWhiteSpace( value?.ToString() );
        }

        #endregion
    }
}
